﻿///////////////////////////////////////////////////////////////////////////////
/// Copyright (c) by longshuang@msn.cn 2014.
/// All rights reserved.
///
/// @File	: Engine.Script.hpp
/// @Brief	: 提供对Lua Official C API的便捷封装
/// @Author	: Leo Zhao <longshuang@msn.cn>
/// @Date	: 2015-01-26
///
/// CHANGELOG
/// 	2015-01-26	初版提交
///////////////////////////////////////////////////////////////////////////////
#ifndef		__ENGINE_SCRIPT_HPP_INCLUDE__
#define		__ENGINE_SCRIPT_HPP_INCLUDE__

extern "C" {
#	include		"Lua/lua.h"
#	include		"Lua/lualib.h"
#	include		"Lua/lauxlib.h"
}

#include	<algorithm>
#include	<cstdint>
#include	<cstring>
#include	<stdexcept>
#include	<string>
#include	<vector>

#define		GScripter			Engine::Lua::Script::Instance()
#define		LUA_GUARD_START		try {
#define		LUA_GUARD_END		} catch (std::runtime_error &) {}

/// 内部接口，工具
namespace Engine { namespace Lua {
	extern void	lua_rawgetfield(lua_State * pL, int nIdx, char const * pKey);
	extern void lua_rawsetfield(lua_State * pL, int nIdx, char const * pKey);
	extern bool	lua_isfulluserdata(lua_State * pL, int nIdx);
	extern void	lua_printerror(lua_State * pL);

	class Reference;
	class Table;
	class Stack;
	class Script;
	class Nil;

	template<class T>
	struct Class2Meta {
		static std::string	Meta;
		static bool			Used;
		static int			RefIdx;
	};
	template<class T> std::string	Class2Meta<T>::Meta		= "Unknown";
	template<class T> bool			Class2Meta<T>::Used		= false;
	template<class T> int			Class2Meta<T>::RefIdx	= 0;

	class Cleaner {
	public:
		Cleaner(lua_State * pL, int nNum) : _pL(pL), _nNum(nNum) {}
		virtual ~Cleaner() { if (_pL) lua_pop(_pL, std::min(lua_gettop(_pL), _nNum)); }

	private:
		lua_State *	_pL;
		int			_nNum;
	};

	template<typename T> struct StackHelper {
		enum { Type = (1 << LUA_TNONE), OrgType = LUA_TNONE };
		typedef T * &	RefType;
	};
	template<typename T> struct StackHelper < T * > {
		enum { Type = (1 << LUA_TLIGHTUSERDATA) | (1 << LUA_TUSERDATA), OrgType = LUA_TUSERDATA };
		typedef T * 	RefType;
		static T *		Get(lua_State * pL, int nIdx) {
			return static_cast<T *>(lua_touserdata(pL, nIdx));
		}
		static void		Set(lua_State * pL, T * pData) {
			T ** pUserData = static_cast<T **>(lua_newuserdata(pL, sizeof(T *)));
			*pUserData = pData;
			luaL_getmetatable(pL, Class2Meta<T>::Meta.c_str());
			if (lua_isnil(pL, -1)) {
				luaL_error(pL, "Class %s not registered!", Class2Meta<T>::Meta.c_str());
			}

			lua_setmetatable(pL, -2);
		}
	};
	template<> struct StackHelper < bool > {
		enum { Type = (1 << LUA_TBOOLEAN) | (1 << LUA_TNIL) | (1 << LUA_TNUMBER), OrgType = LUA_TBOOLEAN };
		typedef bool	RefType;
		static bool		Get(lua_State * pL, int nIdx) { return 1 == lua_toboolean(pL, nIdx); }
		static void		Set(lua_State * pL, bool bValue) { lua_pushboolean(pL, bValue); }
	};
	template<> struct StackHelper < char > {
		enum { Type = 1 << LUA_TNUMBER, OrgType = LUA_TNUMBER };
		typedef char	RefType;
		static char		Get(lua_State * pL, int nIdx) { return lua_tointeger(pL, nIdx) & 0xFF; }
		static void		Set(lua_State * pL, char nValue) { lua_pushinteger(pL, nValue); }
	};
	template<> struct StackHelper < uint8_t > {
		enum { Type = 1 << LUA_TNUMBER, OrgType = LUA_TNUMBER };
		typedef uint8_t	RefType;
		static uint8_t	Get(lua_State * pL, int nIdx) { return lua_tointeger(pL, nIdx) & 0xFF; }
		static void		Set(lua_State * pL, uint8_t nValue) { lua_pushinteger(pL, nValue); }
	};
	template<> struct StackHelper < int8_t > {
		enum { Type = 1 << LUA_TNUMBER, OrgType = LUA_TNUMBER };
		typedef int8_t	RefType;
		static int8_t	Get(lua_State * pL, int nIdx) { return lua_tointeger(pL, nIdx) & 0xFF; }
		static void		Set(lua_State * pL, int8_t nValue) { lua_pushinteger(pL, nValue); }
	};
	template<> struct StackHelper < uint16_t > {
		enum { Type = 1 << LUA_TNUMBER, OrgType = LUA_TNUMBER };
		typedef uint16_t	RefType;
		static uint16_t	Get(lua_State * pL, int nIdx) { return lua_tointeger(pL, nIdx) & 0xFFFF; }
		static void		Set(lua_State * pL, uint16_t nValue) { lua_pushinteger(pL, nValue); }
	};
	template<> struct StackHelper < int16_t > {
		enum { Type = 1 << LUA_TNUMBER, OrgType = LUA_TNUMBER };
		typedef int16_t	RefType;
		static int16_t	Get(lua_State * pL, int nIdx) { return lua_tointeger(pL, nIdx) & 0xFFFF; }
		static void		Set(lua_State * pL, int16_t nValue) { lua_pushinteger(pL, nValue); }
	};
	template<> struct StackHelper < uint32_t > {
		enum { Type = 1 << LUA_TNUMBER, OrgType = LUA_TNUMBER };
		typedef uint32_t	RefType;
		static uint32_t	Get(lua_State * pL, int nIdx) { return lua_tointeger(pL, nIdx) & 0xFFFFFFFF; }
		static void		Set(lua_State * pL, uint32_t nValue) { lua_pushinteger(pL, nValue); }
	};
	template<> struct StackHelper < int32_t > {
		enum { Type = 1 << LUA_TNUMBER, OrgType = LUA_TNUMBER };
		typedef int32_t	RefType;
		static int32_t	Get(lua_State * pL, int nIdx) { return lua_tointeger(pL, nIdx) & 0xFFFFFFFF; }
		static void		Set(lua_State * pL, int32_t nValue) { lua_pushinteger(pL, nValue); }
	};
	template<> struct StackHelper < uint64_t > {
		enum { Type = 1 << LUA_TNUMBER, OrgType = LUA_TNUMBER };
		typedef uint64_t	RefType;
		static uint64_t	Get(lua_State * pL, int nIdx) { return lua_tointeger(pL, nIdx); }
		static void		Set(lua_State * pL, uint64_t nValue) { lua_pushinteger(pL, (ptrdiff_t)nValue); }
	};
	template<> struct StackHelper < int64_t > {
		enum { Type = 1 << LUA_TNUMBER, OrgType = LUA_TNUMBER };
		typedef int64_t	RefType;
		static int64_t	Get(lua_State * pL, int nIdx) { return lua_tointeger(pL, nIdx) & 0xFFFF; }
		static void		Set(lua_State * pL, int64_t nValue) { lua_pushinteger(pL, (ptrdiff_t)nValue); }
	};
	template<> struct StackHelper < double > {
		enum { Type = 1 << LUA_TNUMBER, OrgType = LUA_TNUMBER };
		typedef double	RefType;
		static double	Get(lua_State * pL, int nIdx) { return lua_tonumber(pL, nIdx); }
		static void		Set(lua_State * pL, double nValue) { lua_pushnumber(pL, nValue); }
	};
	template<> struct StackHelper < const char * > {
		enum { Type = 1 << LUA_TSTRING, OrgType = LUA_TSTRING };
		typedef const char *	RefType;
		static const char *	Get(lua_State * pL, int nIdx) { size_t nLen = 0; return lua_tolstring(pL, nIdx, &nLen); }
		static void			Set(lua_State * pL, const char * pValue) { lua_pushlstring(pL, pValue, strlen(pValue)); }
	};
	template<int N> struct StackHelper < const char [N] > {
		enum { Type = 1 << LUA_TSTRING, OrgType = LUA_TSTRING };
		typedef const char *	RefType;
		static const char *	Get(lua_State * pL, int nIdx) { size_t nLen = 0; return lua_tolstring(pL, nIdx, &nLen); }
		static void			Set(lua_State * pL, const char * pValue) { lua_pushlstring(pL, pValue, strlen(pValue)); }
	};
	template<> struct StackHelper < std::string > {
		enum { Type = 1 << LUA_TSTRING, OrgType = LUA_TSTRING };
		typedef const std::string &	RefType;
		static std::string	Get(lua_State * pL, int nIdx) { size_t nLen = 0; return lua_tolstring(pL, nIdx, &nLen); }
		static void			Set(lua_State * pL, const std::string & szValue) { lua_pushlstring(pL, szValue.c_str(), szValue.length()); }
	};
	template<> struct StackHelper < lua_CFunction > {
		enum { Type = 1 << LUA_TFUNCTION, OrgType = LUA_TFUNCTION };
		typedef lua_CFunction	RefType;
		static lua_CFunction	Get(lua_State * pL, int nIdx) { return lua_tocfunction(pL, nIdx); }
		static void				Set(lua_State * pL, lua_CFunction fnOpt) { lua_pushcfunction(pL, fnOpt); }
	};
	
	template<> struct StackHelper < Nil > ;
	template<> struct StackHelper < Reference > ;
	template<> struct StackHelper < Table > ;

	template<typename ... Args> struct StackMultiHelper {
		template<typename Head, typename ... Tail>
		static void Set(lua_State * pL, Head && hValue, Tail ... tails) {
			StackHelper<typename std::remove_reference<Head>::type>::Set(pL, hValue);
			StackMultiHelper<Args...>::Set(pL, tails...);
		}

		template<typename Head>
		static void Set(lua_State * pL, Head && hValue) {
			StackHelper<typename std::remove_reference<Head>::type>::Set(pL, hValue);
		}

		static void Set(lua_State * pL) {}
	};

	struct StackCaller {
		template<typename FuncType>
		static int	Call(lua_State * pL, FuncType fnOpt);

		template<typename T, typename FuncType>
		static int	Call(lua_State * pL, T * pUserData, FuncType fnOpt);
	};

	struct TraceBackProxy {
		static int Proc(lua_State * pL);
	};

	struct ClassExtensionProxy {
		static int Proc(lua_State * pL);
	};

	struct RequireProxy {
		static int Proc(lua_State * pL);
	};
	
	struct JumperProxy {
		static int Proc(lua_State * pL);
	};

	struct ReadOnlyProxy {
		static int Proc(lua_State * pL);
	};

	struct MetaTableProxy {
		static int Index(lua_State * pL);
		static int NewIndex(lua_State * pL);
		static int Func(lua_State * pL);

		template<typename T>
		static int Getter(lua_State * pL) {
			if (!lua_islightuserdata(pL, lua_upvalueindex(1))) {
				luaL_error(pL, "Get property error!");
				return 0;
			}

			T const * pData = static_cast <T const *> (lua_touserdata(pL, lua_upvalueindex(1)));
			if (!pData) {
				luaL_error(pL, "Get property error! nil");
				return 0;
			}

			StackHelper<T>::Set(pL, *pData);
			return 1;
		}

		template<typename T>
		static int Setter(lua_State * pL) {
			if (!lua_islightuserdata(pL, lua_upvalueindex(1))) {
				luaL_error(pL, "Set property error!");
				return 0;
			}

			T * pData = static_cast <T *> (lua_touserdata(pL, lua_upvalueindex(1)));
			if (!pData) {
				luaL_error(pL, "Set property error! nil");
				return 0;
			}

			*pData = StackHelper<T>::Get(pL, 1);
			return 0;
		}

		template<typename T>
		static int FuncGetter(lua_State * pL) {
			int nIdx = lua_upvalueindex(1);
			if (!lua_isfulluserdata(pL, nIdx)) {
				luaL_error(pL, "Get property by setter error!");
				return 0;
			}

			typedef T(*GetFunc)();
			GetFunc * pFunc = static_cast <GetFunc *> (lua_touserdata(pL, lua_upvalueindex(1)));
			if (!pFunc) {
				luaL_error(pL, "Get property by getter error! nil");
				return 0;
			}
			T tValue = (*pFunc)();
			StackHelper<T>::Set(pL, tValue);
			return 1;
		}

		template<typename T>
		static int FuncSetter(lua_State * pL) {
			int nIdx = lua_upvalueindex(1);
			if (!lua_isfulluserdata(pL, nIdx)) {
				luaL_error(pL, "Set property by setter error!");
				return 0;
			}

			typedef void(*SetFunc)(typename StackHelper<T>::RefType);
			SetFunc * pFunc = static_cast <SetFunc *> (lua_touserdata(pL, lua_upvalueindex(1)));
			if (!pFunc) {
				luaL_error(pL, "Set property by setter error! nil");
				return 0;
			}

			(*pFunc)(StackHelper<T>::Get(pL, 1));
			return 0;
		}
	};

	template<class T>
	struct ClassMetaTableProxy {
		static int Index(lua_State * pL) {
			int nRes = 0;

			if (!lua_isuserdata(pL, 1)) return nRes;
			lua_getmetatable(pL, 1);

			while (true) {
				lua_pushvalue(pL, 2);
				lua_rawget(pL, -2);
				if (lua_iscfunction(pL, -1) || lua_isfunction(pL, -1)) {
					lua_remove(pL, -2);
					nRes = 1;
					break;
				} else if (lua_isnil(pL, -1)) {
					lua_pop(pL, 1);
				} else {
					luaL_error(pL, "Index '%s' of class '%s' must be a cfunction, but current '%s'!", lua_tostring(pL, 2), Class2Meta<T>::Meta.c_str(), lua_typename(pL, lua_type(pL, -1)));
				}

				lua_rawgetfield(pL, -1, "__propget");
				if (lua_istable(pL, -1)) {
					lua_pushvalue(pL, 2);
					lua_rawget(pL, -2);
					lua_remove(pL, -2);
					if (lua_iscfunction(pL, -1)) {
						lua_pushvalue(pL, 1);
						lua_rotate(pL, 1, 2);
						lua_pop(pL, 3);
						lua_call(pL, 1, 1);
						nRes = 1;
						break;
					} else if (lua_isnil(pL, -1)) {
						luaL_error(pL, "Try to index '%s' of class '%s' which is a nil value!", lua_tostring(pL, 2), Class2Meta<T>::Meta.c_str());
					} else {
						luaL_error(pL, "Index '%s' of class '%s' must be a cfunction, but current '%s'!", lua_tostring(pL, 2), Class2Meta<T>::Meta.c_str(), lua_typename(pL, lua_type(pL, -1)));
					}
				} else {
					luaL_error(pL, "Class '%s' missing __propget table!");
				}
			}

			return nRes;
		}

		static int NewIndex(lua_State * pL) {
			int nRes = 0;
			lua_getmetatable(pL, 1);
			while (true) {
				lua_rawgetfield(pL, -1, "__propset");
				if (!lua_isnil(pL, -1)) {
					lua_pushvalue(pL, 2);
					lua_rawget(pL, -2);
					if (!lua_isnil(pL, -1)) {
						if (!lua_isfunction(pL, -1)) return nRes;
						lua_pushvalue(pL, 1);
						lua_pushvalue(pL, 3);
						lua_call(pL, 2, 0);
						nRes = 0;
						break;
					} else {
						luaL_error(pL, "Try index '%s' of class '%s' which is a nil value!", lua_tostring(pL, 2), Class2Meta<T>::Meta.c_str());
					}
				} else {
					luaL_error(pL, "Class '%s' missing __propset!", Class2Meta<T>::Meta.c_str());
				}
			}
			return nRes;
		}

		static int ToString(lua_State * pL) {
			T ** pObj = static_cast<T **>(lua_touserdata(pL, 1));
			lua_pushfstring(pL, "Class[%s:%p]", Class2Meta<T>::Meta.c_str(), *pObj);
			return 1;
		}

		static int Func(lua_State * pL) {
			if (lua_gettop(pL) < 1) {
				luaL_error(pL, "Class '%s' call function error syntax. Use ':' instead of '.'!", Class2Meta<T>::Meta.c_str());
			}

			int nFuncIdx = lua_upvalueindex(1);
			if (!lua_isfulluserdata(pL, nFuncIdx) || !lua_isfulluserdata(pL, 1)) {
				luaL_error(pL, "Class '%s' call func error!", Class2Meta<T>::Meta.c_str());
				return 0;
			}

			typedef int (T::*CFunc)(Stack &);
			CFunc * fnOpt = static_cast<CFunc *>(lua_touserdata(pL, nFuncIdx));
			T ** pClass = static_cast<T **>(lua_touserdata(pL, 1));
			if (!fnOpt) {
				luaL_error(pL, "Class '%s' Try to call an undefined method!", Class2Meta<T>::Meta.c_str());
				return 0;
			}
			return StackCaller::Call(pL, *pClass, *fnOpt);
		}
	};

	template<typename T, typename P>
	struct ClassMemberProxy {
		static int Getter(lua_State * pL) {
			if (!lua_isuserdata(pL, lua_upvalueindex(1))) {
				luaL_error(pL, "Class '%s' get property error!", Class2Meta<T>::Meta.c_str());
				return 0;
			}

			T ** pClass = static_cast<T **>(lua_touserdata(pL, 1));
			P T::** pData = static_cast <P T::**> (lua_touserdata(pL, lua_upvalueindex(1)));
			if (!pData) {
				luaL_error(pL, "Class '%s' get property error! nil", Class2Meta<T>::Meta.c_str());
				return 0;
			}

			StackHelper<P>::Set(pL, (*pClass)->**pData);
			return 1;
		}

		static int Setter(lua_State * pL) {
			if (!lua_isuserdata(pL, lua_upvalueindex(1))) {
				luaL_error(pL, "Class '%s' set property error!", Class2Meta<T>::Meta.c_str());
				return 0;
			}

			T ** pClass = static_cast<T **>(lua_touserdata(pL, 1));
			P T::** pData = static_cast <P T::**> (lua_touserdata(pL, lua_upvalueindex(1)));
			if (!pData) {
				luaL_error(pL, "Class '%s' set property error! nil", Class2Meta<T>::Meta.c_str());
				return 0;
			}

			(*pClass)->**pData = StackHelper<P>::Get(pL, 2);
			return 0;
		}

		static int FuncGetter(lua_State * pL) {
			int nIdx = lua_upvalueindex(1);
			if (!lua_isfulluserdata(pL, nIdx) || !lua_isfulluserdata(pL, 1)) {
				luaL_error(pL, "Class '%s' set property by setter error!", Class2Meta<T>::Meta.c_str());
				return 0;
			}

			T ** pClass = static_cast<T **>(lua_touserdata(pL, 1));

			typedef P(T::*GetFunc)();
			GetFunc * pFunc = static_cast <GetFunc *> (lua_touserdata(pL, lua_upvalueindex(1)));
			if (!pFunc) {
				luaL_error(pL, "Class '%s' get property by getter error! nil", Class2Meta<T>::Meta.c_str());
				return 0;
			}

			StackHelper<P>::Set(pL, ((*pClass)->**pFunc)());
			return 1;
		}

		static int FuncSetter(lua_State * pL) {
			int nIdx = lua_upvalueindex(1);
			if (!lua_isfulluserdata(pL, nIdx) || !lua_isfulluserdata(pL, 1)) {
				luaL_error(pL, "Class '%s' set property by setter error!", Class2Meta<T>::Meta.c_str());
				return 0;
			}

			T ** pClass = static_cast<T **>(lua_touserdata(pL, 1));

			typedef void (T::*SetFunc)(typename StackHelper<P>::RefType);
			SetFunc * pFunc = static_cast <SetFunc *> (lua_touserdata(pL, lua_upvalueindex(1)));
			if (!pFunc) {
				luaL_error(pL, "Class '%s' set property by setter error! nil", Class2Meta<T>::Meta.c_str());
				return 0;
			}

			P tValue = StackHelper<P>::Get(pL, 2);
			((*pClass)->**pFunc)(tValue);
			return 0;
		}
	};

}}

typedef		Engine::Lua::Table	LuaTable;
typedef		Engine::Lua::Stack	LuaStack;

/// 外部接口，工具
namespace Engine { namespace Lua {

	/// @Brief	: Lua中Nil的C++描述
	class Nil {};

	template<> struct StackHelper < Nil > {
		enum { Type = 1 << LUA_TNIL, OrgType = LUA_TNIL };
		typedef const Nil &	RefType;
		static void			Set(lua_State * pL, const Nil & iNil) { lua_pushnil(pL); }
	};

	/// @Brief	: Lua中元素的C++描述
	class Reference {
	public:
		Reference(lua_State * pL = 0, int nIdx = LUA_NOREF);
		Reference(const Reference & rIns);
		virtual ~Reference();

		/// @Brief	: 拷贝函数
		/// @Param	: rIns		目标Reference
		/// @Return	: 返回拷贝后的对象
		Reference &		operator=(const Reference & rIns);

		/// @Brief	: 取得当前的Type
		/// @Param	: NONE
		/// @Return	: 返回Lua中定义的类型枚举
		int		Type();

		/// @Brief	: 压入栈中
		/// @Param	: NONE
		/// @Return	: NONE
		void	Push();

		/// @Brief	: 从栈中弹出
		/// @Param	: NONE
		/// @Return	: NONE
		void	Pop();

		/// @Brief	: 释放对Lua中某元素的引用
		/// @Param	: NONE
		/// @Return	: NONE
		void	Release();

		/// @Brief	: 判断当前栈中的某个元素是否为指定类型
		/// @Param	: nIdx		元素在栈中的位置
		/// @Return	: TRUE为指定类型
		template<typename T>
		bool	Is() {
			if (_nIdx == LUA_NOREF) return false;
			int nType = 1 << Type();
			return (StackHelper<T>::Type & nType) != 0;
		}		

	protected:
		lua_State *		_pL;
		int				_nIdx;
	};

	template<> struct StackHelper < Reference > {
		enum { Type = 0xFFFF, OrgType = 0xFFFF };
		typedef Reference &	RefType;
		static Reference	Get(lua_State * pL, int nIdx) { lua_pushvalue(pL, nIdx); return Reference(pL, luaL_ref(pL, LUA_REGISTRYINDEX)); }
		static void			Set(lua_State * pL, Reference & iRef) { iRef.Push(); }
	};

	/// @Brief	: Lua与C++的栈
	class Stack {
	public:
		Stack(lua_State * pL, bool bNeedPop = true);
		virtual ~Stack();

		/// @Brief	: 获得当前栈中元素个数
		/// @Param	: NONE
		/// @Return	: 返回当前栈中元素个数
		int				Top();

		/// @Brief	: 从栈顶开始，弹出N个元素
		/// @Param	: nCount	弹出元素的个数
		/// @Return	: NONE
		void			Pop(int nCount);

		/// @Brief	: 获取当前栈中的某个元素类型
		/// @Param	: nIdx		元素在栈中的位置
		/// @Return	: 类型的描述
		const char *	TypeName(int nIdx);

		/// @Brief	: 取得lua_State对象
		/// @Param	: NONE
		/// @Return	: 返回lua_State指针
		lua_State *		GetCState();
		
		/// @Brief	: 判断当前栈中的某个元素是否为指定类型
		/// @Param	: nIdx		元素在栈中的位置
		/// @Return	: TRUE为指定类型
		template<typename T>
		bool			Is(int nIdx) {
			if (lua_absindex(_pL, nIdx) > lua_gettop(_pL)) return false;
			int nType = 1 << lua_type(_pL, nIdx);
			return (StackHelper<T>::Type & nType) != 0;
		}

		/// @Brief	: 获得一个Table中的某个元素
		/// @Param	: nIdx		元素在Table栈中的位置
		/// @Return	: 返回该元素的C++描述
		template<typename T>
		T				Get(int nIdx) {
			if (lua_absindex(_pL, nIdx) > lua_gettop(_pL))
				luaL_error(_pL, "Want to get param %d, but stack number is %d", nIdx, lua_gettop(_pL));

			int nType = lua_type(_pL, nIdx);
			if (!((1 << nType) & StackHelper<T>::Type)) {
				luaL_error(_pL, "Get index '%d' error, %s expected but got %s!", nIdx, lua_typename(_pL, StackHelper<T>::OrgType), lua_typename(_pL, nType));
			}

			return StackHelper<T>::Get(_pL, nIdx);
		}

		/// @Brief	: 入栈一个参数
		/// @Param	: tValue	需要入栈的参数
		/// @Return	: NONE
		template<typename T>
		void			Push(typename StackHelper<T>::RefType tValue) {
			StackHelper<T>::Set(_pL, tValue);
		}

	private:
		lua_State *		_pL;
		bool			_bNeedPop;
	};

	template<typename FuncType>
	int StackCaller::Call(lua_State * pL, FuncType fnOpt) {
		Stack iStack(pL, false);
		return fnOpt(iStack);
	}

	template<typename T, typename FuncType>
	int StackCaller::Call(lua_State * pL, T * pUserData, FuncType fnOpt) {
		Stack iStack(pL, false);
		return (pUserData->*fnOpt)(iStack);
	}

	/// @Brief	: 名空间注册操作工具
	class GlobalRegister : public Reference {
	public:
		GlobalRegister(lua_State * pL, int nRef) : Reference(pL, nRef) {}

		/// @Brief	: 注册新的全局函数
		/// @Param	: szFunc	函数在Lua中的Key
		/// @Param	: fnOpt		GlobalFunc形式的函数指针
		/// @Return	: 返回Reference本身
		GlobalRegister &	AddFunction(const char * szFunc, int(*fnOpt)(Stack &));

		/// @Brief	: 注册属性值。不可在_G中使用Property方法
		/// @Param	: szKey		属性在Lua中访问的Key
		/// @Param	: pData		属性值指针
		/// @Param	: bWritable	属性是否可写
		/// @Return	: 返回Reference本身
		template<typename T>
		GlobalRegister &	AddProperty(const char * szKey, T * pData, bool bWritable = true) {
			Push();

			lua_getfield(_pL, -1, "__propget");
			if (!lua_istable(_pL, -1)) {
				luaL_error(_pL, "add property on a table has no metatable!");
				return *this;
			}

			lua_pushlightuserdata(_pL, pData);
			lua_pushcclosure(_pL, &MetaTableProxy::Getter<T>, 1);
			lua_rawsetfield(_pL, -2, szKey);
			lua_pop(_pL, 1);

			lua_getfield(_pL, -1, "__propset");
			if (!lua_istable(_pL, -1)) {
				luaL_error(_pL, "add property on a table has no metatable!");
				return *this;
			}

			if (bWritable) {
				lua_pushlightuserdata(_pL, pData);
				lua_pushcclosure(_pL, &MetaTableProxy::Setter<T>, 1);
			} else {
				lua_pushstring(_pL, szKey);
				lua_pushcclosure(_pL, &ReadOnlyProxy::Proc, 1);
			}
			lua_rawsetfield(_pL, -2, szKey);
			lua_pop(_pL, 2);

			return *this;
		}

		/// @Brief	: 注册属性值（getter，setter方式）
		/// @Param	: szKey		属性在Lua中访问的Key
		/// @Param	: fnGetter	获取该属性的函数
		/// @Param	: fnSetter	设置该属性的函数，只读可不填
		/// @Return	: 返回Reference本身
		template<typename T>
		GlobalRegister &	AddProperty(const char * szKey, T(*fnGetter)(), void(*fnSetter)(typename StackHelper<T>::RefType) = 0) {
			Push();

			lua_getfield(_pL, -1, "__propget");
			if (!lua_istable(_pL, -1)) {
				luaL_error(_pL, "add property on a table has no metatable!");
				return *this;
			}

			typedef T(*Getter)();
			new (lua_newuserdata(_pL, sizeof(Getter))) Getter(fnGetter);
			lua_pushcclosure(_pL, &MetaTableProxy::FuncGetter<T>, 1);
			lua_rawsetfield(_pL, -2, szKey);
			lua_pop(_pL, 1);

			lua_getfield(_pL, -1, "__propset");
			if (!lua_istable(_pL, -1)) {
				luaL_error(_pL, "add property on a table has no metatable!");
				return *this;
			}

			if (fnSetter) {
				typedef void(*Setter)(typename StackHelper<T>::RefType);
				new (lua_newuserdata(_pL, sizeof(Setter))) Setter(fnSetter);
				lua_pushcclosure(_pL, &MetaTableProxy::FuncSetter<T>, 1);
			} else {
				lua_pushstring(_pL, szKey);
				lua_pushcclosure(_pL, &ReadOnlyProxy::Proc, 1);
			}
			lua_rawsetfield(_pL, -2, szKey);
			lua_pop(_pL, 2);

			return *this;
		}
	};

	/// @Brief	: C++注册类操作工具
	template<typename T>
	class ClassRegister : public Reference {
	public:
		ClassRegister(lua_State * pL, int nRef, const char * szKey, bool bNeedInit = true) : Reference(pL, nRef) {
			if (bNeedInit) {
				Class2Meta<T>::Meta		= szKey;
				Class2Meta<T>::RefIdx	= nRef;
				Class2Meta<T>::Used		= true;
			}			
		}

		/// @Brief	: 注册成员变量
		/// @Param	: szKey		属性在Lua中访问的Key
		/// @Param	: pData		属性值指针
		/// @Param	: bWritable	属性是否可写
		/// @Return	: 返回Reference本身
		template<typename P>
		ClassRegister<T> &	AddProperty(const char * szKey, P T::* pData, bool bWritable = true) {
			LUA_GUARD_START
			Push();
			lua_rawgetfield(_pL, -2, "__propget");
			if (!lua_istable(_pL, -1)) {
				luaL_error(_pL, "add property on a table has no metatable!");
				return *this;
			}

			typedef P T::*U;
			new (lua_newuserdata(_pL, sizeof(U))) U(pData);
			lua_pushcclosure(_pL, &ClassMemberProxy<T, P>::Getter, 1);
			lua_rawsetfield(_pL, -2, szKey);
			lua_pop(_pL, 1);

			lua_rawgetfield(_pL, -1, "__propset");
			if (!lua_istable(_pL, -1)) {
				luaL_error(_pL, "add property on a table has no metatable!");
				return *this;
			}

			if (bWritable) {
				new (lua_newuserdata(_pL, sizeof(U))) U(pData);
				lua_pushcclosure(_pL, &ClassMemberProxy<T, P>::Setter, 1);
			} else {
				lua_pushstring(_pL, szKey);
				lua_pushcclosure(_pL, &ReadOnlyProxy::Proc, 1);
			}
			lua_rawsetfield(_pL, -2, szKey);
			lua_pop(_pL, 2);
			LUA_GUARD_END

			return *this;
		}

		/// @Brief	: 注册属性值（getter，setter方式）
		/// @Param	: szKey		属性在Lua中访问的Key
		/// @Param	: fnGetter	获取该属性的函数
		/// @Param	: fnSetter	设置该属性的函
		/// @Return	: 返回注册工具本身
		template<typename P>
		ClassRegister<T> &		AddProperty(const char * szKey, P(T::*fnGetter)(), void (T::*fnSetter)(typename StackHelper<P>::RefType) = 0) {
			LUA_GUARD_START
			Push();

			lua_rawgetfield(_pL, -1, "__propget");
			if (!lua_istable(_pL, -1)) {
				luaL_error(_pL, "add property on a table has no metatable!");
				return *this;
			}

			typedef P(T::*Getter)();
			new (lua_newuserdata(_pL, sizeof(Getter))) Getter(fnGetter);
			lua_pushcclosure(_pL, &ClassMemberProxy<T, P>::FuncGetter, 1);
			lua_rawsetfield(_pL, -2, szKey);
			lua_pop(_pL, 1);

			lua_rawgetfield(_pL, -1, "__propset");
			if (!lua_istable(_pL, -1)) {
				luaL_error(_pL, "add property on a table has no metatable!");
				return *this;
			}

			if (fnSetter) {
				typedef void (T::*Setter)(typename StackHelper<P>::RefType);
				new (lua_newuserdata(_pL, sizeof(Setter))) Setter(fnSetter);
				lua_pushcclosure(_pL, &ClassMemberProxy<T, P>::FuncSetter, 1);
			} else {
				lua_pushstring(_pL, szKey);
				lua_pushcclosure(_pL, &ReadOnlyProxy::Proc, 1);
			}
			lua_rawsetfield(_pL, -2, szKey);
			lua_pop(_pL, 2);
			LUA_GUARD_END

			return *this;
		}

		/// @Brief	: 注册新的成员函数
		/// @Param	: szFunc	函数在Lua中的Key
		/// @Param	: fnOpt		CMemFunc形式的函数指针
		/// @Return	: 返回Reference本身
		ClassRegister<T> &	AddFunction(const char * szFunc, int (T::*fnOpt)(Stack &)) {
			LUA_GUARD_START
			Push();
			typedef int (T::*ClassMemFunc)(Stack &);
			new (lua_newuserdata(_pL, sizeof(ClassMemFunc))) ClassMemFunc(fnOpt);
			lua_pushcclosure(_pL, &ClassMetaTableProxy<T>::Func, 1);
			lua_rawsetfield(_pL, -2, szFunc);
			lua_pop(_pL, 1);
			LUA_GUARD_END
			return *this;
		}

	};

	/// @Brief	: Lua中Table的C++描述
	class Table : public Reference {
	public:
		Table(lua_State * pL = 0, int nRef = LUA_NOREF);
		Table(const Reference & iIns);
		Table(Stack & rStack);

		/// @Brief	: 获得一个Table中的某个元素
		/// @Param	: nIdx		元素在Table栈中的位置
		/// @Return	: 返回该元素的C++描述
		template<typename T>
		T			Get(int nIdx) {
			lua_rawgeti(_pL, LUA_REGISTRYINDEX, _nIdx);
			lua_rawgeti(_pL, -1, nIdx);

			Cleaner iCleaner(_pL, 2);

			int nType = lua_type(_pL, -1);
			if (!((1 << nType) & StackHelper<T>::Type)) {
				luaL_error(_pL, "Get index '%d' error, %s expected but got %s!", nIdx, lua_typename(_pL, StackHelper<T>::OrgType), lua_typename(_pL, nType));
			}
			return StackHelper<T>::Get(_pL, -1);
		}

		/// @Brief	: 获得一个Table中的某个元素
		/// @Param	: szKey		元素在Table中的Key
		/// @Return	: 返回该元素的C++描述
		template<typename T>
		T			Get(const char * szKey) {
			lua_rawgeti(_pL, LUA_REGISTRYINDEX, _nIdx);
			lua_getfield(_pL, -1, szKey);

			Cleaner iCleaner(_pL, 2);

			int nType = lua_type(_pL, -1);
			if (!((1 << nType) & StackHelper<T>::Type)) {
				luaL_error(_pL, "Get key '%s' error, %s expected but got %s!", szKey, lua_typename(_pL, StackHelper<T>::OrgType), lua_typename(_pL, nType));
			}
			return StackHelper<T>::Get(_pL, -1);
		}

		/// @Brief	: 设置一个Table中的值
		/// @Param	: nIdx		元素在Table中的索引
		/// @Param	: tValue	新值
		/// @Return	: NONE
		template<typename T>
		void		Set(int nIdx, typename StackHelper<T>::RefType tValue) {
			lua_rawgeti(_pL, LUA_REGISTRYINDEX, _nIdx);
			StackHelper<T>::Set(_pL, tValue);
			lua_rawseti(_pL, -2, nIdx);
			lua_pop(_pL, 1);
		}

		/// @Brief	: 设置一个Table中的值
		/// @Param	: szKey		元素在Table中的Key
		/// @Param	: tValue	新值
		/// @Return	: NONE
		template<typename T>
		void		Set(const char * szKey, typename StackHelper<T>::RefType tValue) {
			lua_rawgeti(_pL, LUA_REGISTRYINDEX, _nIdx);
			StackHelper<T>::Set(_pL, tValue);
			lua_setfield(_pL, -2, szKey);
			lua_pop(_pL, 1);
		}

		/// @Brief	: 执行该Table下的某个函数（Table.Func()方式调用，不含self）
		/// @Param	: szFunc	函数的Name，不可包含':'与'.'号
		/// @Param	: nRet		该函数期望的返回值个数
		/// @Param	: args ...	函数需要的参数
		/// @Return	: 返回执行完成后当前的栈
		template<typename ... Args>
		Stack		Call(const char * szFunc, int nRet, Args && ... args) {
			int nCall = 0, nType = LUA_TNIL;

			LUA_GUARD_START
			lua_rawgeti(_pL, LUA_REGISTRYINDEX, _nIdx);
			lua_getfield(_pL, -1, szFunc);
			lua_remove(_pL, -2);
			nType = lua_type(_pL, -1);
			if (nType == LUA_TNIL) {
				lua_pop(_pL, 1);
				luaL_error(_pL, "attempt to call a function '%s' which is not exists!", szFunc);
			} else if (nType != LUA_TFUNCTION) {
				lua_pop(_pL, 1);
				luaL_error(_pL, "'%s' is not a function but %s", szFunc, lua_typename(_pL, nType));
			}
			
			StackMultiHelper<Args ...>::Set(_pL, args...);

			int nFuncIdx = lua_gettop(_pL) - sizeof ... (Args);
			lua_pushcfunction(_pL, &TraceBackProxy::Proc);
			lua_insert(_pL, nFuncIdx);
			nCall = lua_pcall(_pL, sizeof ... (Args), nRet, nFuncIdx);
			lua_remove(_pL, nFuncIdx);
			if (nCall != 0) lua_printerror(_pL);
			lua_gc(_pL, LUA_GCCOLLECT, 0);
			LUA_GUARD_END

			return Stack(_pL);
		}

		/// @Brief	: 执行该Table下的某个函数（Table:Func()方式调用，含self）
		/// @Param	: szFunc	函数的Name，不可包含':'与'.'号
		/// @Param	: nRet		该函数期望的返回值个数
		/// @Param	: args ...	函数需要的参数
		/// @Return	: 返回执行完成后当前的栈
		template<typename ... Args>
		Stack		SelfCall(const char * szFunc, int nRet, Args && ... args) {
			int nCall = 0, nType = LUA_TNIL;

			LUA_GUARD_START
			lua_rawgeti(_pL, LUA_REGISTRYINDEX, _nIdx);
			lua_getfield(_pL, -1, szFunc);
			nType = lua_type(_pL, -1);
			if (nType == LUA_TNIL) {
				lua_pop(_pL, 2);
				luaL_error(_pL, "attempt to call a function '%s' which is not exists!", szFunc);
			} else if (nType != LUA_TFUNCTION) {
				lua_pop(_pL, 2);
				luaL_error(_pL, "'%s' is not a function but %s", szFunc, lua_typename(_pL, nType));
			}

			lua_pushvalue(_pL, -2);
			lua_remove(_pL, -3);

			StackMultiHelper<Args ...>::Set(_pL, args...);

			int nFuncIdx = lua_gettop(_pL) - sizeof ... (Args)-1;
			lua_pushcfunction(_pL, &TraceBackProxy::Proc);
			lua_insert(_pL, nFuncIdx);
			nCall = lua_pcall(_pL, sizeof ... (Args)+1, nRet, nFuncIdx);
			lua_remove(_pL, nFuncIdx);
			if (nCall != 0) lua_printerror(_pL);
			lua_gc(_pL, LUA_GCCOLLECT, 0);
			LUA_GUARD_END

			return Stack(_pL);
		}
	};

	template<> struct StackHelper < Table > {
		enum { Type = 1 << LUA_TTABLE, OrgType = LUA_TTABLE };
		typedef Table &		RefType;
		static Table		Get(lua_State * pL, int nIdx) { lua_pushvalue(pL, nIdx); return Table(pL, luaL_ref(pL, LUA_REGISTRYINDEX)); }
		static void			Set(lua_State * pL, Table & iRef) { iRef.Push(); }
	};

	/// @Brief	: Lua的解析器
	class Script {
	public:
		Script();
		virtual ~Script();

		/// @Brief	: 获得运行期单例对象
		/// @Param	: NONE
		/// @Return	: 返回运行期单例对象
		static Script &	Instance();
		
		/// @Brief	: 运行脚本文件
		/// @Param	: szFile	脚本文件的路径
		/// @Param	: bForce	是否强制加载（非require方式）
		/// @Return	: NONE
		void		DoFile(const char * szFile, bool bForce = false);

		/// @Brief	: 运行脚本代码
		/// @Param	: szCode	脚本代码
		/// @Return	: NONE
		void		DoString(const char * szCode);

		/// @Brief	: 全局变量获取
		/// @Param	: szKey		全局变量的Key
		/// @Return	: 返回全局变量
		template<typename T>
		T			Get(const char * szKey) {
			lua_getglobal(_pL, szKey);
			int nType = lua_type(_pL, -1);
			if (!((1 << nType) & StackHelper<T>::Type))
				luaL_error(_pL, "Call Script::Get(%s) Error : '%s' expected but got '%s'!", szKey, lua_typename(_pL, StackHelper<T>::OrgType), lua_typename(_pL, nType));
			Cleaner iAuto(_pL, 1);
			return StackHelper<T>::Get(_pL, -1);
		}

		/// @Brief	: 设置全局变量
		/// @Param	: szKey		全局变量的Key
		/// @Param	: tValue	全局变量的值
		/// @Return	: NONE
		template<typename T>
		void		Set(const char * szKey, typename StackHelper<T>::RefType tValue) {
			StackHelper<T>::Set(_pL, tValue);
			lua_setglobal(_pL, szKey);
		}

		/// @Brief	: 执行全局函数
		/// @Param	: szFunc	函数的Name，不可包含':'与'.'号
		/// @Param	: nRet		该函数期望的返回值个数
		/// @Param	: args ...	函数需要的参数
		/// @Return	: 返回执行完成后当前的栈
		template<typename ... Args>
		Stack		Call(const char * szFunc, int nRet, Args && ... args) {
			int nCall = 0, nType = LUA_TNIL;

			LUA_GUARD_START
			lua_getglobal(_pL, szFunc);
			nType = lua_type(_pL, -1);
			if (nType == LUA_TNIL) {
				lua_pop(_pL, 1);
				luaL_error(_pL, "attempt to call global function '%s' which is not exists!", szFunc);
			} else if (nType != LUA_TFUNCTION) {
				lua_pop(_pL, 1);
				luaL_error(_pL, "'%s' is not global function but %s", szFunc, lua_typename(_pL, nType));
			}

			StackMultiHelper<Args ...>::Set(_pL, args...);

			int nFuncIdx = lua_gettop(_pL) - sizeof ... (Args);
			lua_pushcfunction(_pL, &TraceBackProxy::Proc);
			lua_insert(_pL, nFuncIdx);
			nCall = lua_pcall(_pL, sizeof ... (Args), nRet, nFuncIdx);
			lua_remove(_pL, nFuncIdx);
			if (nCall != 0) lua_printerror(_pL);
			lua_gc(_pL, LUA_GCCOLLECT, 0);
			LUA_GUARD_END

			return Stack(_pL);
		}

		/// @Brief	: 注册新的C++名空间(含有Meta的Table)
		/// @Param	: szSpace	名空间
		/// @Return	: 返回该名空间(含有Meta的Table)
		GlobalRegister		Register(const char * szSpace);

		/// @Brief	: 向Lua中注册一个Class，采用C++管理生存域，所以Lua中不再有Constructer与Destructor
		/// @Param	: szClass	Lua中的类名
		/// @Return	: 返回该类
		template<class T>
		ClassRegister<T>	Register(const char * szClass) {
			if (Class2Meta<T>::Used) return ClassRegister<T>(_pL, Class2Meta<T>::RefIdx, szClass, false);

			if (luaL_newmetatable(_pL, szClass) == 0) {
				luaL_error(_pL, "Bad key '%s' for register lua class, already exists with type %s!", szClass, lua_typename(_pL, lua_type(_pL, -1)));
			}
			
			lua_pushcfunction(_pL, &ClassMetaTableProxy<T>::Index);
			lua_rawsetfield(_pL, -2, "__index");
			lua_pushcfunction(_pL, &ClassMetaTableProxy<T>::NewIndex);
			lua_rawsetfield(_pL, -2, "__newindex");
			lua_pushcfunction(_pL, &ClassMetaTableProxy<T>::ToString);
			lua_rawsetfield(_pL, -2, "__tostring");
			lua_newtable(_pL);
			lua_rawsetfield(_pL, -2, "__propget");
			lua_newtable(_pL);
			lua_rawsetfield(_pL, -2, "__propset");
			
			return ClassRegister<T>(_pL, luaL_ref(_pL, LUA_REGISTRYINDEX), szClass);
		}

		/// @Brief	: 取得当前栈
		/// @Param	: NONE
		/// @Return	: 返回当前栈的描述
		Stack			GetStack();

	private:
		Script(const Script &) = delete;
		Script &	operator=(const Script &) = delete;
		
	private:
		lua_State *					_pL;
		std::vector<std::string>	_vLoaded;
	};

}}

#endif//!	__ENGINE_SCRIPT_HPP_INCLUDE__
